package com.rrkd.handler;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;

import com.rrkd.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rrkd.model.RequestFile;
import com.rrkd.model.ResponseFile;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class BigFileBySpiltServerHandler extends ChannelInboundHandlerAdapter{
private static final Logger log = LoggerFactory.getLogger(FileTransferServerHandler.class);
	
	private volatile int byteRead;
	private volatile long start = 0;
	
	/**
	 * 文件默认存储地址
	 */
	//private String file_dir =FileTransferProperties.getString("file_write_path","/");
	private String file_dir ="";
	private RandomAccessFile randomAccessFile; 
	private File file ;
	private long fileSize = -1 ;

	private String destPaths="";
	
	@Override
	public  void channelRead(ChannelHandlerContext ctx, Object msg)  {
		if (msg instanceof RequestFile) {
			RequestFile ef = (RequestFile) msg;
			byte[] bytes = ef.getBytes();
			byteRead = ef.getEndPos();
			destPaths=ef.getUploadDestPath();
			String sm3 = ef.getSM3();//文件MD5值
			//start=ef.getStarPos();//获得文件的起始位置
			if(start == 0){ //只有在文件开始传的时候才进入 这样就减少了对象创建 和可能出现的一些错误
				//String path = file_dir + File.separator + ef.getFile_name() + ef.getFile_type();
				file_dir=destPaths+File.separator+ef.getParent();
				file = new File(file_dir);
				fileSize = ef.getLocalfile_size();
				if(!file.exists()){
					file.mkdirs();
				}
				file=new File(file_dir+File.separator+ef.getFile_name() + ef.getFile_type());
				fileSize = ef.getLocalfile_size();
				
				//path=file_dir+File.separator+ef.getParent() + File.separator + ef.getFile_name()+ef.getFile_type();//文件分块之后的文件路径处理需要跟客户端的文件名一致
				//file=new File(path);
				
				//根据 MD5 和 文件类型 来确定是否存在这样的文件 如果存在就 秒传
				if( file.exists() ) {
					
					log.info("file exists:" + ef.getFile_name()+"--" +ef.getSM3() +"[" + ctx.channel().remoteAddress()+"]");
					ResponseFile responseFile = new ResponseFile(start,sm3,getFilePath(),"传输完成");
					ctx.writeAndFlush(responseFile);
					
					//TODO 这里可以做 断点续传 ，读取当前已经存在文件的总长度  和 传输过来的文件总长度对比 如果不一致，则认为本地文件没有传完毕 则续传
					// 不过这步骤必须做好安全之后来做，否则可能会出现 文件被恶意加入内容
					return ;
				}
				
				try {
					randomAccessFile = new RandomAccessFile(file, "rw");
				} catch (FileNotFoundException e) {
					
					log.info(e.toString());
				}
			}
			
			try {
				randomAccessFile.seek(start);
				randomAccessFile.write(bytes, 0, byteRead);
				start = start + byteRead;
				
				if (byteRead > 0 && (start < fileSize && fileSize != -1)) {
					//log.info((start*100)/fileSize+"::::" +fileSize+"::: " +(start*100));
					ResponseFile responseFile = new ResponseFile(start,sm3,(start*100)/fileSize);
					ctx.writeAndFlush(responseFile);
				} else {
					log.info("create file success:" +ef.getFile_name()+"--" +ef.getSM3() +"[" + ctx.channel().remoteAddress() +"]");
					FileUtils.CheckSM3andCrc(file,ef.getSM3(),ef.getCrc());
					ResponseFile responseFile = new ResponseFile(start,sm3,getFilePath(),"传输完成");
					ctx.writeAndFlush(responseFile);
					start=0;
					randomAccessFile.close();
					
					fileSize = -1;
					randomAccessFile = null;
					//ctx.close();  这步让客户端来做
					
					if(file.getParentFile().listFiles().length==ef.getTempsize()){
						//分块的临时文件传输完成对文件进行合并
						//destPath=file_dir+ef.getSourceParent();
						FileUtils.merge(file.getParentFile(), destPaths,ef.getSourceFiletype());
						FileUtils.deleteFile(file.getParentFile().getAbsolutePath());//删除临时文件
						
					}
				}
			} catch (IOException e) {
				log.info("磁盘空间可能不足，请磁盘内存");
				log.info(e.toString());
				ResponseFile responseFile = new ResponseFile(getFilePath(),"服务端磁盘空间不足，请磁盘内存");
				ctx.writeAndFlush(responseFile);
			}

		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		
		//当连接断开的时候 关闭未关闭的文件流
		if(randomAccessFile != null ){
			try {
				randomAccessFile.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		ctx.close();
	}
	
	/**
	 * 获取 文件路径
	 * @return
	 */
	private String getFilePath(){
		if( file != null )
			return FileTransferProperties.getString("download_root_path") +"/" + file.getName();
		else 
			return null ;
	}
	
}
